﻿// main.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <osgViewer/viewer>
#include <osgEarth/Notify>
#include <osgEarth/EarthManipulator>
#include <osgEarth/MapNode>
#include <osgEarth/Threading>
#include <osgEarth/ShaderGenerator>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgUtil/Optimizer>
#include <iostream>
#include <osgEarth/Metrics>
#include <osgEarth/GDAL>

#include <osgEarth/OGRFeatureSource>
#include <osgEarth/FeatureDisplayLayout>
#include <osgEarth/FeatureModelLayer>
#include <osgEarth/TMS>
#include <osgEarth/XYZ>


#include <osgEarth/TerrainEngineNode>

#include <osgEarth/TFS> //tiled feature services

#include <osgEarth/SimplePager>
#include "SimpleOsmBuildingsLayer.h"

using namespace osgEarth;
using namespace osgEarth::Util;
#include <iostream>
#include <sstream>
#include <cassert>
using namespace std;
//SKY
#include "osgEarthDrivers\sky_simple\SimpleSkyNode"//for the sky
#include "osgEarthDrivers\sky_simple\SimpleSkyOptions"//for the sky

//Mouse coordinate Tools
#include <osgEarth/MouseCoordsTool>
string g_myMouseCallbackText;
SkyNode* g_skyNode = nullptr;
osgEarth::MapNode* g_mapNode = nullptr;

struct MyMouseCallback :public osgEarth::Contrib::MouseCoordsTool::Callback
{
	virtual void 	set(const GeoPoint& coords, osg::View* view, MapNode* mapNode);
	virtual void 	reset(osg::View* view, MapNode* mapNode);
};
void MyMouseCallback::set(const GeoPoint& coords, osg::View* view, MapNode* mapNode) {
	stringstream ss;
	ss << "Lon:" << coords.x() << ",Lat:" << coords.y() << ",Alt:" << coords.alt();
	g_myMouseCallbackText = ss.str();
}
void MyMouseCallback::reset(osg::View* view, MapNode* mapNode) {
	g_myMouseCallbackText = "Lon:---,Lat:---,Alt:---";//lon , lat , alt
}
struct MyMapNodeCallback :osg::NodeCallback
{
	MyMapNodeCallback(osgViewer::Viewer* viewer):_viewer(viewer){ }
	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
	osg::observer_ptr<SimpleOSMBuildingsLayer> _osmLayer;
protected:
	bool _mcToolInited = false;
	osg::observer_ptr<osgViewer::Viewer> _viewer;
	bool _osmInstalled = false;
	
};
void MyMapNodeCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
	osgEarth::MapNode* mapNode = dynamic_cast<osgEarth::MapNode*>(node);
	if (mapNode) {
		if (_osmLayer.valid() && _osmInstalled==false) {
			_osmInstalled = true;
			
			mapNode->getLayerNodeGroup()->addChild(_osmLayer.get());
			_osmLayer->build();
		}
		if (mapNode->getTerrainEngine()) {
			//Mouse Coords
			if (_mcToolInited == false) {
				_mcToolInited = true;
				osg::ref_ptr<osgEarth::Contrib::MouseCoordsTool> mouseCoordsTool = new osgEarth::Contrib::MouseCoordsTool(mapNode);
				mouseCoordsTool->addCallback(new MyMouseCallback);
				_viewer->addEventHandler(mouseCoordsTool);
			}
		}
	}
	traverse(node, nv);
}

class FindSkyNodeVisitor :public osg::NodeVisitor {
public:
	FindSkyNodeVisitor() :osg::NodeVisitor(NODE_VISITOR, TRAVERSE_ALL_CHILDREN) {}
	virtual void apply(osg::Group& node) {
		SkyNode* sky = dynamic_cast<SkyNode*>(&node);
		if (sky != nullptr) {
			g_skyNode = sky;
		}
		else {
			traverse(node);
		}
	}
};
class FindSkyCallback :public osg::NodeCallback {
public:
	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
		if (g_skyNode == nullptr) {
			FindSkyNodeVisitor findSkyVisitor;
			node->accept(findSkyVisitor);
			traverse(node, nv);
		}
		else {
			return;
		}
	}
};

//IMGUI
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "OsgImGuiHandler.hpp"
//初始化IMGUI
class ImGuiInitOperation : public osg::Operation
{
public:
	ImGuiInitOperation()
		: osg::Operation("ImGuiInitOperation", false){}
	void operator()(osg::Object* object) override
	{
		osg::GraphicsContext* context = dynamic_cast<osg::GraphicsContext*>(object);
		if (!context)return;
		if (!ImGui_ImplOpenGL3_Init()){std::cout << "ImGui_ImplOpenGL3_Init() failed\n";}
	}
};
//IMGUI控件绘制类
class MyIMGuiHandler : public OsgImGuiHandler
{
public:
	MyIMGuiHandler() {}
protected:
	void drawUi() override //绘制控件
	{
		// ImGui code goes here...
		ImGui::Begin("tut-30");
		ImGui::Text("hours");
		float tempHours = _hours;
		ImGui::SliderFloat("slider", &tempHours, 0.0f, 4.f);
		if (tempHours != _hours) {
			_hours = tempHours;
			if (g_skyNode != nullptr) {
				float dayhour = 24 * (_hours - floorf(_hours));
				const osgEarth::DateTime& dt = g_skyNode->getDateTime();
				osgEarth::DateTime dt1(dt.year(), dt.month(), dt.day(), dayhour);
				g_skyNode->setDateTime(dt1);
			}
		}
		ImGui::Text(g_myMouseCallbackText.c_str());
		ImGui::End();
	}
private:
	float _hours = 0;
};

int main()
{
	cout << "version 1.3.1.0 remove debug infos, testing codes and nonsense comments for gitee." << endl; 
	cout<<"v2.0.0.1r using init demdata to create building heights."<<endl;
	osgEarth::initialize();
	//create a viewer
	osgViewer::Viewer viewer;
	viewer.setUpViewInWindow(0, 100, 1280, 720);
	viewer.setReleaseContextAtEndOfFrameHint(false);
	//set camera manipulator
	EarthManipulator* manipulate = new EarthManipulator;
	viewer.setCameraManipulator(manipulate);
	osg::ref_ptr<osgEarth::Map> map = new osgEarth::Map();
	//bg osm
	XYZImageLayer* bgLayer = new XYZImageLayer();
	bgLayer->setURL(osgEarth::URI("https://tile-a.openstreetmap.fr/hot/{z}/{x}/{y}.png"));
	bgLayer->setProfile(Profile::create(Profile::SPHERICAL_MERCATOR));//need this for XYZ
	map->addLayer(bgLayer);
	////elevation
	TMSElevationLayer* elev = new TMSElevationLayer();
	elev->setURL(osgEarth::URI("http://readymap.org/readymap/tiles/1.0.0/116/"));
	elev->setVerticalDatum("egm96");
	elev->setMinLevel(0);
	elev->setMaxLevel(15);
	map->addLayer(elev);
	//MapNode
	osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map.get());
	viewer.setSceneData(mapNode);
	MyMapNodeCallback* myMapNodeCallback = new MyMapNodeCallback(&viewer);
	mapNode->addUpdateCallback(myMapNodeCallback);
	g_mapNode = mapNode.get();
	if (true)//this is my osmbuildings staffs
	{
		string demFilename = "beihuqu_dem_30m_cog.tif";
		SimpleOSMBuildingsLayer* myOSMBuildingsLayer = new SimpleOSMBuildingsLayer(map,mapNode.get(), demFilename, 4,8);
		//myOSMBuildingsLayer->setUrl("http://localhost:8080/beijing_osmbuildings_tiles/{z}/{x}/{y}.json");
		myOSMBuildingsLayer->setUrl("http://localhost:8080/chenzhou/osmbuildings/{z}/{x}/{y}.json");
		myMapNodeCallback->_osmLayer = myOSMBuildingsLayer;
	}
	if(true){//SKY
		//SkyOptions options;
		osgEarth::SimpleSky::SimpleSkyOptions options;
		options.quality() = SkyOptions::QUALITY_DEFAULT;
		options.ambient() = 0.01;//控制环境光强度
		options.exposure() = 10.f;//控制白天的亮度
		options.atmosphereVisible() = true;//大气层厚度是否可见
		options.atmosphericLighting() = true;//大气散射光是否可见
		options.sunVisible() = true;
		options.moonVisible() = true;
		options.starsVisible() = true;
		options.usePBR() = true;
		//添加天空模型
		mapNode->addExtension(Extension::create("sky_simple", options));//这里不能使用addChild, Extension是一种更复杂的对象
	}
	Viewpoint viewPoint1("Beijing", 116.143,40.2472, 139 , 45, -45, 2000);
	Viewpoint viewPoint2("Hunan Chenzhou", 113.025 , 25.75 , 0 , 0 , -80 , 5000);
	manipulate->setViewpoint(viewPoint2, 5);
	//IMGUI
	viewer.setRealizeOperation(new ImGuiInitOperation);//imgui
	viewer.addEventHandler(new MyIMGuiHandler);//imgui
	viewer.getCamera()->addUpdateCallback(new FindSkyCallback);
	return Metrics::run(viewer);
}